//*****************************************************************************
//
// Interrupt based serial communciation example code
//
//
//  When data is recieved at the serial port the microcontroller places that data into
//  the packetbuffer.  This Example write the contents of the buffer out of the serial
//  port.
//*****************************************************************************

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/rom.h"
#include "grlib/grlib.h"
#include "drivers/cfal96x64x16.h"
#include "utils/uartstdio.h"
#include "utils/crc.h"
#include "CommandProcessing.h"

#include "driverlib/adc.h"

//*****************************************************************************
//
// Initalize Global Variables
//
//*****************************************************************************
#ifndef TRUE
	#define TRUE 1
#endif

#ifndef FALSE
	#define FALSE 0
#endif

#define packetbuffer_size 21
unsigned char packetbuffer[packetbuffer_size];
unsigned int packetbuffer_pos = 0;
struct packetHeader
{
	unsigned short OpCode;
	char PacketDataLength;
};

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif

//*****************************************************************************
//
// LIFTI VerifyPacket function. Verify actual CRC with packet CRC
//
//*****************************************************************************
	int VerifyPacket(char* packet) {
		unsigned char PacketDataLength = packet[2];
		//sizeof (struct PacketHeader)
		unsigned int PacketLength = 3 + PacketDataLength; //Not including CRC
		unsigned short packetCRC = *((unsigned short *)(packet + PacketLength)); //Pull CRC16 from Packet
		unsigned short actualCRC = Crc16(0, (const unsigned char *)packet, PacketLength);	//Calculate CRC16 from recv'd data

		//Debug
	//	UARTprintf("PacketLength=%u ", PacketDataLength);
	//	UARTprintf("packetCRC=0x%x ", packetCRC);	  //doesnt display the full CRC value
//		UARTprintf("actualCRC=0x%x ", actualCRC);

		if (actualCRC == packetCRC)
		{
			return TRUE;
		}
		else
		{
			return FALSE;
		}

	}
//*****************************************************************************
//
// LIFTI GetPacket function. Pulls Packet from Receive buffer into local buffer
//
//*****************************************************************************
	int GetPacket (char* local_buffer) {
		unsigned char PacketDataLength;
		unsigned char PacketLength;
		int i;

		//Check if receive buffer has enough chars in it
		// Need at least 2 byte opcode + 1 byte lenght + ?? bytes data + 2 bytes CRC
		PacketDataLength = packetbuffer[2];
		PacketLength = PacketDataLength + 5;
		if (packetbuffer_pos < PacketLength)
			return FALSE;
		
		if (PacketLength > packetbuffer_size) //This is an absolute no-no & most likely a non-recoverable error
		{
			packetbuffer_pos = 0;  //Delete all packets received and start over
			//Send packet to host that this happened
			//fixme
			return FALSE;
		}

		//Disable Receive Interrupts
		//fixme

		//Copy packet from receive buffer into local buffer
		for (i = 0; i < PacketLength; i++) 
		{
			local_buffer[i] = packetbuffer[i];
		}
		//Update buffer length
		packetbuffer_pos -= (PacketLength);
		//Shift buffer PacketLength bytes to the left
		for (i = 0; i < packetbuffer_pos; i++) 
		{
			packetbuffer[i] = packetbuffer[i + (PacketLength)];
		}

		//Enable Receive Interrupts
		//fixme

		return TRUE;
	}

//*****************************************************************************
//
// The UART interrupt handler.
//
//*****************************************************************************
void
UARTIntHandler(void)
{
    unsigned long ulStatus;

    //
    // Get the interrrupt status.
    //
    ulStatus = ROM_UARTIntStatus(UART0_BASE, true);

    //
    // Clear the asserted interrupts.
    //
    ROM_UARTIntClear(UART0_BASE, ulStatus);

    //
    // Loop while there are characters in the receive FIFO.
    //
    while(ROM_UARTCharsAvail(UART0_BASE) && (packetbuffer_pos <= packetbuffer_size))
    {
        //
        // Read the next character from the UART and write it to the packetbuffer.
        //
        packetbuffer[packetbuffer_pos++] = ROM_UARTCharGetNonBlocking(UART0_BASE);
    }
}
//*****************************************************************************
//
// Runs the Startup and intialization procedures
//
//*****************************************************************************

void 
InterfaceSetup(void)
{
	//
    // Enable lazy stacking for interrupt handlers.  This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPULazyStackingEnable();

    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    //
    // Enable the peripherals used by this example.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Enable processor interrupts.
    //
    ROM_IntMasterEnable();

    //
    // Set GPIO A0 and A1 as UART pins.
    //
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Configure the UART for 115,200, 8-N-1 operation.
    //
    ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));

    //
    // Enable the UART interrupt.
    //
    ROM_IntEnable(INT_UART0);
    ROM_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
	//
    // Initialize the UART.
    //
    UARTStdioInit(0);
	// 
	// Set packetbuffer position to 0
	//
	packetbuffer_pos = 0;
}


//*****************************************************************************
//
// This example demonstrates how to send a string of data to the UART.
//
//*****************************************************************************
int
main(void)
{
 	//
	// Create variable for keeping track of local buffer
	//
	char local_buf[20];
	unsigned int previouspacketbuffer_pos = 0;


    //
    // This array is used for storing the data read from the ADC FIFO. It
    // must be as large as the FIFO for the sequencer in use.  This example
    // uses sequence 3 which has a FIFO depth of 1.  If another sequence
    // was used with a deeper FIFO, then the array size must be changed.
    //
    unsigned long ulADC0_Value[1];




	// 
	// Run the Setup commands for inteface communication
	//
	InterfaceSetup();


//1#ifdef AITEST
    //
    // Display the setup on the console.
    //
    //UARTprintf("ADC ->\n");
    //UARTprintf("  Type: Single Ended\n");
    //UARTprintf("  Samples: One\n");
    //UARTprintf("  Update Rate: 250ms\n");
    //UARTprintf("  Input Pin: AIN0/PE7\n\n");

    //
    // The ADC0 peripheral must be enabled for use.
    //
    //1SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //
    // For this example ADC0 is used with AIN0 on port E7.
    // The actual port and pins used may be different on your part, consult
    // the data sheet for more information.  GPIO port E needs to be enabled
    // so these pins can be used.
    // TODO: change this to whichever GPIO port you are using.
    //
    //1SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    //
    // Select the analog ADC function for these pins.
    // Consult the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using.
    //
    //1GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_7);

    //
    // Enable sample sequence 3 with a processor signal trigger.  Sequence 3
    // will do a single sample when the processor sends a signal to start the
    // conversion.  Each ADC module has 4 programmable sequences, sequence 0
    // to sequence 3.  This example is arbitrarily using sequence 3.
    //
    //1ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);

    //
    // Configure step 0 on sequence 3.  Sample channel 0 (ADC_CTL_CH0) in
    // single-ended mode (default) and configure the interrupt flag
    // (ADC_CTL_IE) to be set when the sample is done.  Tell the ADC logic
    // that this is the last conversion on sequence 3 (ADC_CTL_END).  Sequence
    // 3 has only one programmable step.  Sequence 1 and 2 have 4 steps, and
    // sequence 0 has 8 programmable steps.  Since we are only doing a single
    // conversion using sequence 3 we will only configure step 0.  For more
    // information on the ADC sequences and steps, reference the datasheet.
    //
	//#define CHAN_ACCELX     ADC_CTL_CH8
	//#define CHAN_ACCELY     ADC_CTL_CH9
	//#define CHAN_ACCELZ     ADC_CTL_CH21
    //1ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH8 | ADC_CTL_IE |
    //1                         ADC_CTL_END);

    //
    // Since sample sequence 3 is now configured, it must be enabled.
    //
    //1ADCSequenceEnable(ADC0_BASE, 3);

    //
    // Clear the interrupt status flag.  This is done to make sure the
    // interrupt flag is cleared before we sample.
    //
    //1ADCIntClear(ADC0_BASE, 3);

    //
    // Sample AIN0 forever.  Display the value on the console.
    //
    //1while(1)
    //1{
        //
        // Trigger the ADC conversion.
        //
        //1ADCProcessorTrigger(ADC0_BASE, 3);

        //
        // Wait for conversion to be completed.
        //
        //1while(!ADCIntStatus(ADC0_BASE, 3, false))
        //1{
        //1}

        //
        // Read ADC Value.
        //
        //1ADCSequenceDataGet(ADC0_BASE, 3, ulADC0_Value);

        //
        // Display the AIN0 (PE7) digital value on the console.
        //
        //1UARTprintf("AIN0 = %4d\r", ulADC0_Value[0]);

        //
        // This function provides a means of generating a constant length
        // delay.  The function delay (in cycles) = 3 * parameter.  Delay
        // 250ms arbitrarily.
        //
        //SysCtlDelay(SysCtlClockGet() / 12);
    //1}




//1#endif










   	//
    // Loop forever handling interrupts and displaying data through the UART.
    //

    while(1)
    {
	 	//
		// Only Write data when packetbuffer_pos changes
		//
			
			
		if(packetbuffer_pos != previouspacketbuffer_pos){ 	 
			//UARTprintf("%u\n%s\n", packetbuffer_pos, packetbuffer);	  
			//UARTprintf("%u\n\n", GetPacket(local_buf)); 			  
			if (GetPacket(local_buf))		
			{
					//UARTprintf("\nRunning\n");
		    	if (VerifyPacket(local_buf))	
          {						
				//		UARTprintf("\nRunning2\n");
		    		ProcessPacket(local_buf,1); 
					}
			}
			previouspacketbuffer_pos = packetbuffer_pos;				  
		}															  
    }
}
